// proxy    代理  13个方法  参数一模一样  es6新增拦截器
// Reflect  反射  13个方法  参数一模一样
// mobx observable  类似Vuex的观察者模式

/* let personObj = {
  name: 'zhangsan',
  age: 18
}

personObj.name        // 取值
personObj.name = 'xxx'// 赋值

// proxy 支持对象  数组  函数  set map  不支持普通类型
let personProxy = new Proxy(personObj, {
  // 取值
  get(target, key, receiver) {},
  // 赋值
  // person name xxx person(在箭头函数中保证上下文能找到person)
  set(target, key, value, receiver) {
    return true
  },
  // 拦截函数调用
  apply() {},
  // 拦截 in 操作符
  has() {
    return true
  },
  // 拦截 for in 操作符
  ownKeys() {
    return []
  },
  // 拦截new操作符
  construct() {
    return {}
  },
  // 拦截 delete 操作符
  deleteProperty() {
    return true
  },
}) */

// 用于测试Proxy.has()
/* var proxyA = 10
proxyA in window */

// 用于测试Proxy.ownKeys()
// for(let key in xxx) {}

/* let personObj = {
  name: 'zhangsan',
  age: 24
}

console.log(Reflect.get(personObj, 'name', personObj))
console.log(Reflect.set(personObj, 'name', '陈浩南', personObj))  // 返回true 说明修改成功
console.log(Reflect.get(personObj, 'name', personObj)) */

/* let personProxy = new Proxy(personObj, {
  get(target:any, key:any, receiver:any) {
    if (target.age <= 18) {
      Reflect.get(target, key, receiver)
    } else {
      return "张三成年啦"
    }
  }
})

console.log(personProxy.name)
console.log(personProxy.age)

personProxy.name = 10 */


// observable用例
const listObs:Set<Function> = new Set()
const autorun = (cb:Function) => {
  if(!listObs.has(cb)) {
    listObs.add(cb)
  }
}

const observableObj = <T extends object>(params:T) => {
  return new Proxy(params, {
    set(target:T, key:string, value:any, receiver:any) {
      const result = Reflect.set(target,key,value,receiver)
      // 如果对象有被修改 则去遍历修改
      listObs.forEach(fn => fn())
      return result
    }
  })
}

const personProxy = observableObj({
  name: '小威',
  attr: "威猛先生"
})

autorun(() => {
  console.log("变化前1")
})

autorun(() => {
  console.log("变化后2")
})

personProxy.attr = "威猛个锤锤"
personProxy.name = "sda1sa"
